/*
GanttProject is an opensource project management tool.
Copyright (C) 2005-2011 GanttProject Team

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package org.ganttproject.impex.htmlpdf;

import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import javax.imageio.ImageIO;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import net.sourceforge.ganttproject.GPLogger;
import net.sourceforge.ganttproject.GanttExportSettings;
import net.sourceforge.ganttproject.export.ExportException;
import net.sourceforge.ganttproject.gui.options.model.GPOptionGroup;
import net.sourceforge.ganttproject.language.GanttLanguage;
import net.sourceforge.ganttproject.util.FileUtil;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.xml.sax.SAXException;

public class ExporterToHTML extends ExporterBase {
    static final String GANTT_CHART_FILE_EXTENSION = "png";
    static final String RESOURCE_CHART_FILE_EXTENSION = "res.png";
    private static final String PNG_FORMAT_NAME = "png";
    private HTMLStylesheet mySelectedStylesheet;
    private final HtmlSerializer mySerializer = new HtmlSerializer(this);

    @Override
    public String getFileTypeDescription() {
        return GanttLanguage.getInstance().getText("impex.html.description");
    }

    @Override
    protected void setSelectedStylesheet(Stylesheet stylesheet) {
        mySelectedStylesheet = (HTMLStylesheet) stylesheet;
    }

    @Override
    public List<GPOptionGroup> getSecondaryOptions() {
        return null;
    }

    @Override
    public String getFileNamePattern() {
        return "html";
    }

    @Override
    protected ExporterJob[] createJobs(File outputFile, List<File> resultFiles) {
        ExporterJob generateGanttChartJob = createGenerateGanttChartJob(outputFile, resultFiles);
        ExporterJob generateResourceChartJob = createGenerateResourceChartJob(outputFile, resultFiles);
        ExporterJob generatePagesJob = createGeneratePagesJob(outputFile, resultFiles);
        ExporterJob copyImagesJob = createCopyImagesJob(outputFile, resultFiles);
        return new ExporterJob[] {
                generateGanttChartJob, generateResourceChartJob, generatePagesJob, copyImagesJob
        };
    }

    private ExporterJob createGenerateGanttChartJob(final File outputFile, final List<File> resultFiles) {
        ExporterJob result = new ExporterJob("generate gantt chart") {
            @Override
            protected IStatus run() {
                try {
                    RenderedImage ganttChartImage = getGanttChart().getRenderedImage(new GanttExportSettings(true, true, true, true));
                    File ganttChartImageFile;
                    ganttChartImageFile = replaceExtension(outputFile, GANTT_CHART_FILE_EXTENSION);
                    ImageIO.write(ganttChartImage, PNG_FORMAT_NAME, ganttChartImageFile);
                    resultFiles.add(ganttChartImageFile);
                } catch (IOException e) {
                    getUIFacade().showErrorDialog(e);
                    return Status.CANCEL_STATUS;
                } catch (OutOfMemoryError e) {
                    getUIFacade().showErrorDialog(new RuntimeException("Out of memory when creating Gantt chart image", e));
                    return Status.CANCEL_STATUS;
                }
                return Status.OK_STATUS;
            }
        };
        return result;
    }

    private ExporterJob createGenerateResourceChartJob(final File outputFile, final List<File> resultFiles) {
        ExporterJob result = new ExporterJob("Generate resource chart") {
            @Override
            protected IStatus run() {
                try {
                    RenderedImage resourceChartImage = getResourceChart().getRenderedImage(new GanttExportSettings(true, true, true, true));
                    File resourceChartImageFile = replaceExtension(outputFile, RESOURCE_CHART_FILE_EXTENSION);
                    ImageIO.write(resourceChartImage, PNG_FORMAT_NAME, resourceChartImageFile);
                    resultFiles.add(resourceChartImageFile);
                } catch (IOException e) {
                    getUIFacade().showErrorDialog(e);
                    return Status.CANCEL_STATUS;
                } catch (OutOfMemoryError e) {
                    getUIFacade().showErrorDialog(new RuntimeException("Out of memory when creating resource chart image", e));
                    return Status.CANCEL_STATUS;
                }
                return Status.OK_STATUS;
            }
        };
        return result;
    }

    private ExporterJob createGeneratePagesJob(final File outputFile, final List<File> resultFiles) {
        ExporterJob result = new ExporterJob("Generate HTML pages") {

            @Override
            protected IStatus run() {
                try {
                    {
                        TransformerHandler handler = mySelectedStylesheet.createTitlePageHandler();
                        handler.setResult(new StreamResult(outputFile));
                        mySerializer.serialize(handler, outputFile);
                        resultFiles.add(outputFile);
                    }
                    {
                        TransformerHandler handler = mySelectedStylesheet.createTasksPageHandler();
                        File tasksPageFile = appendSuffixBeforeExtension(outputFile, "-tasks");
                        handler.setResult(new StreamResult(tasksPageFile));
                        mySerializer.serialize(handler, outputFile);
                        resultFiles.add(tasksPageFile);
                    }
                    {
                        TransformerHandler handler = mySelectedStylesheet.createGanttChartPageHandler();
                        File chartPageFile = appendSuffixBeforeExtension(outputFile, "-chart");
                        handler.setResult(new StreamResult(chartPageFile));
                        mySerializer.serialize(handler, outputFile);
                        resultFiles.add(chartPageFile);
                    }
                    {
                        TransformerHandler handler = mySelectedStylesheet.createResourcesPageHandler();
                        File resourcesPageFile = appendSuffixBeforeExtension(outputFile, "-resources");
                        handler.setResult(new StreamResult(resourcesPageFile));
                        mySerializer.serialize(handler, outputFile);
                        resultFiles.add(resourcesPageFile);
                    }
                } catch (SAXException e) {
                    getUIFacade().showErrorDialog(e);
                    return Status.CANCEL_STATUS;
                } catch (IOException e) {
                    getUIFacade().showErrorDialog(e);
                    return Status.CANCEL_STATUS;
                } catch (OutOfMemoryError e) {
                    getUIFacade().showErrorDialog(new RuntimeException("Out of memory when running XSL transformation", e));
                    return Status.CANCEL_STATUS;
                } catch (ExportException e) {
                    getUIFacade().showErrorDialog(e);
                    return Status.CANCEL_STATUS;
                }
                return Status.OK_STATUS;
            }
        };
        return result;
    }

    private ExporterJob createCopyImagesJob(final File outputFile, final List<File> resultFiles) {
        ExporterJob result = new ExporterJob("Copying images") {
            @Override
            protected IStatus run() {
                try {
                    File imagesDir = mySelectedStylesheet.getImagesDirectory();
                    if (imagesDir != null && imagesDir.isDirectory() && imagesDir.exists()) {
                        File[] lof = imagesDir.listFiles();
                        if (lof.length != 0) {
                            File resultImagesDir = new File(outputFile.getParentFile(), imagesDir.getName());
                            if (resultImagesDir.mkdir()) {
                                for (int i = 0; i < lof.length; i++) {
                                    File nextInFile = lof[i];
                                    if (nextInFile.isDirectory()) {
                                        continue;
                                    }
                                    File outFile = new File(resultImagesDir, nextInFile.getName());
                                    outFile.createNewFile();
                                    FileInputStream inStream = new FileInputStream(nextInFile);
                                    FileOutputStream outStream = new FileOutputStream(outFile);
                                    byte[] buffer = new byte[(int) nextInFile.length()];
                                    inStream.read(buffer);
                                    outStream.write(buffer);
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    getUIFacade().showErrorDialog(e);
                    return Status.CANCEL_STATUS;
                }
                return Status.OK_STATUS;
            }
        };
        return result;
    }

    @Override
    public String proposeFileExtension() {
        return "html";
    }

    @Override
    public String[] getFileExtensions() {
        String s [] = {"html"};
        return s;
    }

    @Override
    protected String getStylesheetOptionID() {
        return "impex.html.stylesheet";
    }

    @Override
    protected List<Stylesheet> getStylesheets() {
        StylesheetFactoryImpl factory = new StylesheetFactoryImpl() {
            @Override
            protected Stylesheet newStylesheet(URL resolvedUrl, String localizedName) {
                return new HTMLStylesheetImpl(resolvedUrl, localizedName);
            }
        };
        return factory.createStylesheets(HTMLStylesheet.class);
    }

    class HTMLStylesheetImpl extends StylesheetImpl implements HTMLStylesheet {
        HTMLStylesheetImpl(URL stylesheetURL, String localizedName) {
            super(stylesheetURL, localizedName);
        }

        @Override
        public String getInputVersion() {
            return HTMLStylesheet.InputVersion.GP1X;
        }

        @Override
        public TransformerHandler createTitlePageHandler() {
            try {
                URL titleUrl = new URL(getUrl(), "gantt.xsl");
                TransformerHandler result = mySerializer.createHandler(titleUrl.toString());
                return result;
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            } catch (TransformerConfigurationException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public TransformerHandler createTasksPageHandler() {
            try {
                URL tasksUrl = new URL(getUrl(), "gantt-tasks.xsl");
                TransformerHandler result = mySerializer.createHandler(tasksUrl.toString());
                return result;
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            } catch (TransformerConfigurationException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public TransformerHandler createGanttChartPageHandler() {
            try {
                URL tasksUrl = new URL(getUrl(), "gantt-chart.xsl");
                TransformerHandler result = mySerializer.createHandler(tasksUrl.toString());
                return result;
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            } catch (TransformerConfigurationException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public TransformerHandler createResourcesPageHandler() {
            try {
                URL tasksUrl = new URL(getUrl(), "gantt-resources.xsl");
                TransformerHandler result = mySerializer.createHandler(tasksUrl.toString());
                return result;
            } catch (MalformedURLException e) {
                throw new RuntimeException(e);
            } catch (TransformerConfigurationException e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public File getImagesDirectory() {
            try {
                URL imagesUrl = new URL(getUrl(), "images");
                File result = new File(imagesUrl.getPath());
                return result;
            } catch (MalformedURLException e) {
                if (!GPLogger.log(e)) {
                    e.printStackTrace(System.err);
                }
                throw new RuntimeException(e);
            }
        }
    }

    private static File appendSuffixBeforeExtension(File f, String suffix) throws IOException {
        return FileUtil.appendSuffixBeforeExtension(f, suffix);
    }

    static File replaceExtension(File f, String newExtension) throws IOException {
        File result = FileUtil.replaceExtension(f, newExtension);
        if (!result.exists()) {
            result.createNewFile();
        }
        return result;
    }

}
